package com.klikmee.sms.core.base;

import java.text.MessageFormat;
import java.util.Map;

import org.apache.log4j.Logger;

import com.klikmee.sms.core.base.communicator.DeliveryReport;
import com.klikmee.sms.core.base.communicator.DeliveryReport2MessageResolver;
import com.klikmee.sms.core.base.exceptions.DeliveryReportNotResolvedException;
import com.klikmee.sms.core.base.handlers.DeliveryReportHandler;
import com.klikmee.sms.core.commons.events.AppEvent;
import com.klikmee.sms.core.commons.events.EventListener;
import com.klikmee.sms.core.model.OutgoingMessage;
/**
 * Implementation of delivery report processor for charged messages.
 * It uses resolvers to resolve charged message and then delegates them to handler.
 * Can be registered to listen for delivery report announcements.
 * @author makcro
 *
 */
public class ChargedDeliveryReportProcessorImpl implements DeliveryReportProcessor, EventListener {

	/**
	 * Logger instance
	 */
	private Logger logger = Logger.getLogger(ChargedDeliveryReportProcessorImpl.class);
	
	/**
	 * Map of delivery report resolvers used to resolve delivery report to send
	 * message. Every {@link DeliveryReport2MessageResolver} instance is mapped
	 * to provider's unique name.
	 */
	private Map<String, DeliveryReport2MessageResolver> deliveryReportResolverMap = null;

	/**
	 * Instance of delivery report handler for charged messages
	 */
	private DeliveryReportHandler deliveryReportHandler;
	
	public void init() {
		logger.debug( MessageFormat.format( "Registered [{0}] delivery resolvers", deliveryReportResolverMap.size() ) );
		logger.debug( MessageFormat.format( "Using [{0}] as delivery report handler", deliveryReportHandler) );
		logger.info( "Charged delivery report handler initialized" );
	}
	
	/**
	 * Processes delivery reports.
	 */
	@Override
	public void process(DeliveryReport deliveryReport) {
		// get delivery report resolver for privier
		DeliveryReport2MessageResolver deliveryReport2MessageResolver = deliveryReportResolverMap.get(deliveryReport.getProvider().getName());
		logger.debug(MessageFormat.format("Using [{0}] delivery resolver", deliveryReport2MessageResolver));

		// try to resolve sent message
		try {
			// this the actual message to be found using data from parameter
			OutgoingMessage sentMessage = deliveryReport2MessageResolver.resolve(deliveryReport);
			logger.debug(MessageFormat.format("Resoved delivery report to outgoing message id = [{0}]", sentMessage.getId()));

			// set status report
			sentMessage.setDeliveryStatus(deliveryReport.getStatus());
			// get payment invoice
			
			this.deliveryReportHandler.handle(sentMessage);
		}
		catch (DeliveryReportNotResolvedException e) {
			
			// this means that resolver could not resolve sent message, usually due to this was a delivery report for bulk message.
			// just log it for debugging
			logger.debug(MessageFormat.format("Could not resolve charged message for delivery report data: {0}, probably bulk, ignorring...", deliveryReport));
		}
	}

	/**
	 * Invoked when new delivery report is announced.
	 * Extracts delivery report from event data and calls {@link #process(DeliveryReport)}
	 * 
	 * @param appEvent event instance to process
	 */
	@Override
	public void handleEvent(AppEvent appEvent) {
		// check if this is expected event type
		String eventType = appEvent.getEventType();
		logger.debug( MessageFormat.format( "Received event notification for type [{0}]", eventType ) );
		
		if(eventType.equals(EventManager.DELIVERY_REPORT_ANNOUNCED)){
			// extract event data
			DeliveryReport deliveryReport = appEvent.<DeliveryReport>getData();
			
			// invoke delivery report processing
			process(deliveryReport);
		}
	}
	
	public Map<String, DeliveryReport2MessageResolver> getDeliveryReportResolverMap() {
		return deliveryReportResolverMap;
	}
	
	public void setDeliveryReportResolverMap(Map<String, DeliveryReport2MessageResolver> deliveryReportResolverMap) {
		this.deliveryReportResolverMap = deliveryReportResolverMap;
	}

	public DeliveryReportHandler getDeliveryReportHandler() {
		return deliveryReportHandler;
	}

	public void setDeliveryReportHandler(DeliveryReportHandler deliveryReportHandler) {
		this.deliveryReportHandler = deliveryReportHandler;
	}
}
